package task.snake.model;

import java.awt.Point;

import task.snake.model.Snake.Eat;

/**
 * Class Frog extends Creature class and describes frog entity. Class provides
 * constructor
 * 
 * @author Nadezhda Makarkina
 * 
 */
public class Frog extends Creature {
	final String TYPE_OF_FROG = "Green";

	/**
	 * Initializes a newly created Frog object.
	 * 
	 * @param p position on play field
	 * @param sm snake model object
	 */
	public Frog(Point p, SnakeModel sm) {
		super(p, sm, sm.getSleepTime() * 3);
	}

	/**
	 * Method returns type of frog.
	 */
	public String getTypeOfFrog() {
		return TYPE_OF_FROG;
	}

	/**
	 * Method generates random number from 0 to 4 so frog will move smartly with
	 * probability 0,8
	 */
	@Override
	public void move() {
		if (onClash(sm.getSnake())) {
			return;
		}
		// if all next cells are busy frog dosn't move, else move
		if (!sm.getCell(body.get(0)).isAllDirectionsBusy()) {
			Point oldPosition = new Point(body.get(0));
			boolean isMoved = false;
			// with probability 0,8 frog will move from snake
			int randForProbability = (int) (Math.random() * 5);
			switch (randForProbability) {
			case 0:
			case 1:
			case 2:
			case 3:
				// coordinates of snake's head and next element after head
				int snakeHeadX = sm.getSnake().getHeadLocation().x;
				int snakeHeadY = sm.getSnake().getHeadLocation().y;
				int snakeBodyX = sm.getSnake().getLocation().get(1).x;
				int snakeBodyY = sm.getSnake().getLocation().get(1).y;
				if (snakeHeadY == snakeBodyY) {// if snake move horizontally
					isMoved = smartMovementWhenSnakeHorizontal(snakeHeadX, snakeHeadY, snakeBodyX,
							snakeBodyY);
				}
				if (snakeHeadX == snakeBodyX) {// when snake move vertically
					isMoved = smartMovementWhenSnakeVertical(snakeHeadX, snakeHeadY, snakeBodyX,
							snakeBodyY);
				}
				break;
			case 4:
				isMoved = chaoticMovement();
				break;
			}
			if (isMoved) {// if frog jump anywhere
				// after movement setup old sell free
				sm.setCell(oldPosition, null, false);
				// and new cell busy
				sm.setCell(getHeadLocation(), this, true);
			}
		}
	}

	private boolean jumpUp() {
		if (!sm.getCell(getHeadLocation()).getUp()) {// if up direction is free
			getHeadLocation().y = getHeadLocation().y - 1;
			return true;
		} else {
			return false;
		}
	}

	private boolean jumpDown() {
		if (!sm.getCell(getHeadLocation()).getDown()) {// if down direction is
														// free
			getHeadLocation().y = getHeadLocation().y + 1;
			return true;
		} else {
			return false;
		}
	}

	private boolean jumpLeft() {
		if (!sm.getCell(getHeadLocation()).getLeft()) {// if left direction is
														// free
			getHeadLocation().x = getHeadLocation().x - 1;
			return true;
		} else {
			return false;
		}
	}

	private boolean jumpRight() {
		if (!sm.getCell(getHeadLocation()).getRight()) {// if right direction is
														// free
			getHeadLocation().x = getHeadLocation().x + 1;
			return true;
		} else {
			return false;
		}
	}

	private boolean smartMovementWhenSnakeHorizontal(int snakeHeadX, int snakeHeadY,
			int snakeBodyX, int snakeBodyY) {
		boolean isMoved = false;
		if (snakeHeadY > getHeadLocation().y) { // move frog up if the snake
												// lower it
			isMoved = jumpUp();
		} else if ((snakeHeadY < getHeadLocation().y)) { // else move down
			isMoved = jumpDown();
		} else { // else if they have the same y coordinate
			// chose direction, opposite nearest wall
			if (getHeadLocation().y > sm.getWidth() - 1 - getHeadLocation().y) {
				isMoved = jumpUp();
			} else {
				isMoved = jumpDown();
			}
		}
		// if up and down directions were busy, then move
		// horizontally
		if (!isMoved) {
			if (snakeHeadX > snakeBodyX) {// when snake moves to the right
				if (snakeHeadX >= getHeadLocation().x) {// move left if the
														// snake has
														// x-coordinate >=that
														// frog
					isMoved = jumpLeft();
				} else {// move right
					isMoved = jumpRight();
				}
			} else {// when snake move to the left do inverse actions
				if (snakeHeadX <= getHeadLocation().x) {
					isMoved = jumpRight();
				} else {
					isMoved = jumpLeft();
				}
			}
		}// in another way it will stay on the same place
		return isMoved;
	}

	private boolean smartMovementWhenSnakeVertical(int snakeHeadX, int snakeHeadY, int snakeBodyX,
			int snakeBodyY) {
		boolean isMoved = false;
		if (snakeHeadX > getHeadLocation().x) {// move frog left if the snake on
												// right side
			isMoved = jumpLeft();
		} else if (snakeHeadX < getHeadLocation().x) {// else move right
			isMoved = jumpRight();
		} else {// else if they have the same x coordinate
			// chose direction, opposite nearest wall
			if (getHeadLocation().x > sm.getWidth() - 1 - getHeadLocation().x) {
				isMoved = jumpLeft();
			} else {
				isMoved = jumpRight();
			}
		}
		// if right and left directions were busy, then move
		// vertically
		if (!isMoved) {
			if (snakeHeadX > snakeBodyX) {// when snake move to the down
				if (snakeHeadY >= getHeadLocation().y) {// move up if the snake
														// has y-coordinate
														// >=that frog
					isMoved = jumpUp();
				} else {// move down
					isMoved = jumpDown();
				}
			} else {// when snake move to the up do inverse actions
				if (snakeHeadY <= getHeadLocation().y) {
					isMoved = jumpDown();
				} else {
					isMoved = jumpUp();
				}
			}
		}// in another way it will stay on the same place
		return isMoved;
	}

	/*
	 * Method generates random number from 0 to 3 to move frog 0 - up, 1 -
	 * right, 2 - down, 3 - left and then move frog to new location.
	 */
	private boolean chaoticMovement() {
		boolean stopLoop = false;
		do {
			int rand = (int) (Math.random() * 4);
			switch (rand) {
			case 0:
				stopLoop = jumpUp();
				break;
			case 1:
				stopLoop = jumpRight();
				break;
			case 2:
				stopLoop = jumpDown();
				break;
			case 3:
				stopLoop = jumpLeft();
				break;
			}
		} while (!stopLoop);
		return true;
	}

	/**
	 * Describe situation when frog clashed by the snake.
	 */
	@Override
	public boolean onClash(Snake snake) {
		if (snake.getHeadLocation().equals(this.getHeadLocation())) {
			sm.setCounter(sm.getCounter() + 1);
			// tells snake that it has to grow up while net movement
			snake.setEat(Eat.GREEN_FROG);
			// kills frog and create new one
			for (int i = 0; i < sm.getFrogs().size(); i++) {
				// looks for the frog to kill
				if (sm.getFrogs().get(i) == this) {
					// stops the thread
					sm.getFrogs().get(i).setStopped();
					// sets cell free
					sm.setCell(sm.getFrogs().get(i).getHeadLocation(), null, false);
					// kills old frog
					sm.getFrogs().remove(i);
					// creates new frog
					sm.getFrogs().add(i, sm.createFrog());
					// sets cell busy
					sm.setCell(sm.getFrogs().get(i).getHeadLocation(), sm.getFrogs().get(i), true);
					// creates new thread for it
					Thread t = new Thread(sm.getFrogs().get(i));
					t.setName("Frog " + i);
					// and starts it
					t.start();
					break;
				}
			}
			return true;
		}
		return false;
	}
}
